package com.dingwen.treasure.file.service.impl;

import cn.hutool.core.util.IdUtil;
import com.dingwen.treasure.base.enums.LogicDeleteEnum;
import com.dingwen.treasure.file.component.FileComponent;
import com.dingwen.treasure.file.service.FileService;
import com.dingwen.treasure.minio.service.MinioTemplate;
import com.dingwen.treasure.tkmybatis.entity.TreasureFile;
import com.dingwen.treasure.tkmybatis.service.TreasureFileService;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 　MinioFileServiceImpl
 * 　@author dingwen
 * 　@date 2022/7/4
 */
@Service("minioFileServiceImpl")
public class MinioFileServiceImpl implements FileService {


    /**
     * treasureFileService
     */
    @Resource
    private TreasureFileService treasureFileService;


    /**
     * minioTemplate
     */
    @Resource
    private MinioTemplate minioTemplate;

    @Resource
    private FileComponent fileComponent;

    /**
     * 文件上传
     *
     * @param multipartFile 文件
     * @param treasureFile  文件信息
     * @return {@link List}<{@link TreasureFile}>
     */
    @Override
    @SneakyThrows(Throwable.class)
    public TreasureFile upload(MultipartFile multipartFile, TreasureFile treasureFile) {
        // 完善业务文件信息
        treasureFile = improveTreasureFileInfo(multipartFile, treasureFile);
        minioTemplate.createBucketAndPutObject(
                treasureFile.getBucketName(),
                treasureFile.getObjectName(),
                multipartFile.getInputStream(),
                treasureFile.getFileSize()
        );
        // 注意此处修改了对象
         improveTreasureFileUrl(treasureFile);
        return treasureFileService.add(treasureFile);
    }

    /**
     * 上传
     *
     * @param inputStream  输入流
     * @param treasureFile 文件信息
     * @return {@link TreasureFile}
     */
    @Override
    public TreasureFile upload(InputStream inputStream, TreasureFile treasureFile) {
        minioTemplate.putObject(treasureFile.getBucketName(), treasureFile.getObjectName(), inputStream,
                treasureFile.getFileSize());
        // 注意此处修改了对象
         improveTreasureFileUrl(treasureFile);
        return treasureFileService.add(treasureFile);
    }

    /**
     * 完善文件信息
     *
     * @param multipartFile 文件
     * @param treasureFile  文件信息
     * @return {@link TreasureFile}
     */
    public TreasureFile improveTreasureFileInfo(MultipartFile multipartFile, TreasureFile treasureFile) {
        long size = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();
        String fileName = Optional.ofNullable(treasureFile.getFileName()).orElse(originalFilename);
        assert originalFilename != null;
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        String bucketName = treasureFile.getBucketName().concat(".").concat(fileType);
        String objectName = IdUtil.fastUUID().concat(".").concat(fileType);

        treasureFile.setFileSize(size);
        treasureFile.setOriginalFileName(originalFilename);
        treasureFile.setFileType(fileType);
        treasureFile.setBucketName(bucketName);
        treasureFile.setFileName(fileName);
        treasureFile.setObjectName(objectName);
        treasureFile.setCreateTime(LocalDateTime.now());
        // TODO 当前登录用户
        treasureFile.setCreateBy("treasure");
        return treasureFile;
    }

    /**
     * 文件下载
     *
     * @param fileId   文件id
     * @param request  要求
     * @param response 回答
     */
    @Override
    @Transactional(readOnly = true)
    @SneakyThrows(Throwable.class)
    public void download(Long fileId, HttpServletRequest request, HttpServletResponse response) {
        TreasureFile treasureFile = treasureFileService.getById(fileId);

        //更新下载次数
        treasureFileService.modify(TreasureFile.builder().fileId(fileId).download(treasureFile.getDownload() + 1).build());

        InputStream inputStream = minioTemplate.getInputStream(
                treasureFile.getBucketName(),
                treasureFile.getObjectName()
        );
        String originalFileName = treasureFile.getOriginalFileName();

        fileComponent.doDownload(response, originalFileName, inputStream);
    }

    /**
     * 预览
     *
     * @param fileId   文件id
     * @param response 响应
     */
    @Override
    public void preview(Long fileId, HttpServletResponse response) {
        TreasureFile treasureFile = treasureFileService.getById(fileId);
        Assert.notNull(treasureFile, "文件不存在");
        InputStream inputStream = minioTemplate.getInputStream(
                treasureFile.getBucketName(),
                treasureFile.getObjectName()
        );
        fileComponent.doPreview(response,inputStream);
    }

    /**
     * 删除文件
     *
     * @param fileId 文件id
     */
    @Override
    public void remove(Long fileId) {
        TreasureFile treasureFile = treasureFileService.getById(fileId);
        Assert.notNull(treasureFile, "文件不存在");
        TreasureFile deleteFile = TreasureFile
                .builder()
                .fileId(fileId)
                .deleted(LogicDeleteEnum.DELETED)
                .build();
        treasureFileService.modify(deleteFile);
        minioTemplate.removeObject(treasureFile.getBucketName(), treasureFile.getObjectName());
    }

    /**
     * 完善文件外链信息 <br>
     * 注意此方法修改了调用处方法的对象信息
     * @param treasureFile 文件
     * @return {@link TreasureFile}
     */
    private void improveTreasureFileUrl(TreasureFile treasureFile) {
        String url = minioTemplate.getUrl(treasureFile.getBucketName(), treasureFile.getObjectName(), 7);
        treasureFile.setUrl(url);
    }

}
